#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量发送对话框
用于选择要推送的样本和客户端
"""

import logging
from datetime import datetime, timedelta
from typing import List, Optional
from PyQt6.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QGridLayout, QFormLayout,
    QPushButton, QLabel, QLineEdit, QTextEdit, QTableWidget,
    QTableWidgetItem, QComboBox, QCheckBox, QGroupBox, QMessageBox,
    QProgressBar, QAbstractItemView, QHeaderView, QSplitter, QSizePolicy,
    QRadioButton, QSpinBox, QDateEdit, QTimeEdit
)
from PyQt6.QtCore import Qt, QTimer, pyqtSignal
from PyQt6.QtGui import QFont

try:
    from src.models.models import Sample
    from src.core.sample_push_service import SamplePushService
    from src.core.database_manager import DatabaseManager
except ImportError:
    try:
        from ..models.models import Sample
        from ..core.sample_push_service import SamplePushService
        from ..core.database_manager import DatabaseManager
    except ImportError:
        Sample = None
        SamplePushService = None
        DatabaseManager = None

logger = logging.getLogger(__name__)

class BatchSendDialog(QDialog):
    """批量发送对话框"""
    
    # 信号定义
    push_completed = pyqtSignal(dict)  # 推送完成信号
    
    def __init__(self, push_service: SamplePushService, parent=None, 
                 samples: List[Sample] = None, current_page_samples: List[Sample] = None, 
                 selected_samples: List[Sample] = None):
        super().__init__(parent)
        self.samples = samples or []
        self.current_page_samples = current_page_samples or []
        self.selected_samples = selected_samples or []
        self.push_service = push_service
        self.selected_client = None
        self.is_pushing = False
        self.db_manager = None
        
        self.init_ui()
        self.setup_connections()
        # 延迟加载数据，确保所有UI组件都已创建完成
        QTimer.singleShot(100, self.load_data)
    
    def init_ui(self):
        """初始化界面"""
        self.setWindowTitle("批量发送样本")
        self.setModal(True)
        
        # 自适应窗口大小设置
        self.setMinimumSize(600, 600)  # 减少最小尺寸，因为移除了数据列表
        self.resize(800, 800)          # 减少默认尺寸
        self.setSizeGripEnabled(True)  # 启用大小调整手柄
        
        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setSpacing(10)
        
        # 推送范围组（原样本信息组）
        range_group = QGroupBox("推送范围")
        range_group.setContentsMargins(10, 15, 10, 10)
        range_layout = QVBoxLayout()
        
        # 范围选择
        self.export_latest_radio = QRadioButton("发送最新样本")
        self.export_latest_radio.setChecked(True)
        self.export_latest_radio.toggled.connect(self.on_export_range_changed)
        range_layout.addWidget(self.export_latest_radio)
        
        # 最新样本数量设置
        latest_count_layout = QHBoxLayout()
        latest_count_layout.addWidget(QLabel("数量:"), 0)  # 标签不拉伸，只占用必要空间
        self.latest_count_spinbox = QSpinBox()
        self.latest_count_spinbox.setRange(1, 10000)
        self.latest_count_spinbox.setValue(100)
        self.latest_count_spinbox.setSuffix(" 个")
        self.latest_count_spinbox.setEnabled(True)
        latest_count_layout.addWidget(self.latest_count_spinbox, 1)  # 数量控件拉伸，占用更多空间
        latest_count_layout.addStretch()
        range_layout.addLayout(latest_count_layout)
        
        self.export_time_range_radio = QRadioButton("按时间范围发送")
        self.export_time_range_radio.toggled.connect(self.on_export_range_changed)
        range_layout.addWidget(self.export_time_range_radio)
        
        # 时间范围设置
        # 起始时间
        start_time_layout = QHBoxLayout()
        start_time_layout.setSpacing(2)  # 设置控件间距为2像素，减少多余空间
        start_time_layout.addWidget(QLabel("开始时间:"), 0)  # 标签不拉伸，只占用必要空间
        self.start_date_edit = QDateEdit()
        self.start_date_edit.setDate(datetime.now().date())
        self.start_date_edit.setCalendarPopup(True)
        self.start_date_edit.setEnabled(False)
        start_time_layout.addWidget(self.start_date_edit, 1)  # 日期控件拉伸，占用更多空间
        self.start_time_edit = QTimeEdit()
        self.start_time_edit.setTime(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).time())
        self.start_time_edit.setDisplayFormat("HH:mm")
        self.start_time_edit.setEnabled(False)
        start_time_layout.addWidget(self.start_time_edit, 1)  # 时间控件拉伸，占用更多空间
        range_layout.addLayout(start_time_layout)
        
        # 结束时间
        end_time_layout = QHBoxLayout()
        end_time_layout.setSpacing(2)  # 设置控件间距为2像素，减少多余空间
        end_time_layout.addWidget(QLabel("结束时间:"), 0)  # 标签不拉伸，只占用必要空间
        self.end_date_edit = QDateEdit()
        self.end_date_edit.setDate(datetime.now().date())
        self.end_date_edit.setCalendarPopup(True)
        self.end_date_edit.setEnabled(False)
        end_time_layout.addWidget(self.end_date_edit, 1)  # 日期控件拉伸，占用更多空间
        self.end_time_edit = QTimeEdit()
        self.end_time_edit.setTime(datetime.now().replace(hour=23, minute=59, second=0, microsecond=0).time())
        self.end_time_edit.setDisplayFormat("HH:mm")
        self.end_time_edit.setEnabled(False)
        end_time_layout.addWidget(self.end_time_edit, 1)  # 时间控件拉伸，占用更多空间
        range_layout.addLayout(end_time_layout)
        
        # 快捷时间选择按钮
        quick_time_layout = QHBoxLayout()
        quick_time_layout.setSpacing(2)  # 设置控件间距为2像素，减少多余空间
        quick_time_layout.addWidget(QLabel("快捷选择:"), 0)  # 标签不拉伸，只占用必要空间
        
        self.today_button = QPushButton("今天")
        self.today_button.setMaximumWidth(60)
        self.today_button.clicked.connect(self.set_today_range)
        self.today_button.setEnabled(False)
        quick_time_layout.addWidget(self.today_button)
        
        self.yesterday_button = QPushButton("昨天")
        self.yesterday_button.setMaximumWidth(60)
        self.yesterday_button.clicked.connect(self.set_yesterday_range)
        self.yesterday_button.setEnabled(False)
        quick_time_layout.addWidget(self.yesterday_button)
        
        self.last_7_days_button = QPushButton("最近7天")
        self.last_7_days_button.setMaximumWidth(80)
        self.last_7_days_button.clicked.connect(self.set_last_7_days_range)
        self.last_7_days_button.setEnabled(False)
        quick_time_layout.addWidget(self.last_7_days_button)
        
        self.last_30_days_button = QPushButton("最近30天")
        self.last_30_days_button.setMaximumWidth(80)
        self.last_30_days_button.clicked.connect(self.set_last_30_days_range)
        self.last_30_days_button.setEnabled(False)
        quick_time_layout.addWidget(self.last_30_days_button)
        
        quick_time_layout.addStretch()
        range_layout.addLayout(quick_time_layout)
        
        self.export_all_radio = QRadioButton("发送全部样本")
        self.export_all_radio.toggled.connect(self.on_export_range_changed)
        range_layout.addWidget(self.export_all_radio)
        
        self.export_current_page_radio = QRadioButton("仅发送当前页样本")
        self.export_current_page_radio.toggled.connect(self.on_export_range_changed)
        range_layout.addWidget(self.export_current_page_radio)
        
        self.export_selected_radio = QRadioButton("仅发送选中样本")
        self.export_selected_radio.toggled.connect(self.on_export_range_changed)
        range_layout.addWidget(self.export_selected_radio)
        
        # 更新选中样本数量显示
        self.update_selected_count()
        
        range_group.setLayout(range_layout)
        main_layout.addWidget(range_group)
        
        # TCP服务器状态组
        server_group = QGroupBox("TCP服务器状态")
        server_group.setContentsMargins(10, 15, 10, 10)
        server_layout = QFormLayout()
        server_layout.setSpacing(5)
        
        self.server_status_label = QLabel("未运行")
        self.server_status_label.setStyleSheet("color: red;")
        server_layout.addRow("服务器状态:", self.server_status_label)
        
        self.client_count_label = QLabel("0")
        server_layout.addRow("连接客户端:", self.client_count_label)
        
        self.client_list_combo = QComboBox()
        self.client_list_combo.addItem("所有客户端", None)
        server_layout.addRow("目标客户端:", self.client_list_combo)
        
        server_group.setLayout(server_layout)
        main_layout.addWidget(server_group)
        
        # 推送选项组
        options_group = QGroupBox("推送选项")
        options_group.setContentsMargins(10, 15, 10, 10)
        options_layout = QFormLayout()
        options_layout.setSpacing(5)
        
        self.include_test_results_check = QCheckBox("包含检测结果")
        self.include_test_results_check.setChecked(True)
        options_layout.addRow("", self.include_test_results_check)
        
        self.include_images_check = QCheckBox("包含图片路径")
        self.include_images_check.setChecked(True)
        options_layout.addRow("", self.include_images_check)
        
        self.include_full_database_check = QCheckBox("包含完整数据库内容")
        self.include_full_database_check.setChecked(True)
        self.include_full_database_check.setToolTip("选中后将发送样本的所有数据库字段，包括原始数据")
        options_layout.addRow("", self.include_full_database_check)
        
        options_group.setLayout(options_layout)
        main_layout.addWidget(options_group)
        
        # 进度组
        progress_group = QGroupBox("推送进度")
        progress_group.setContentsMargins(10, 15, 10, 10)  # 减少内边距，适应小窗口
        progress_layout = QVBoxLayout()
        progress_layout.setSpacing(5)  # 减少组件间距
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        progress_layout.addWidget(self.progress_bar)
        
        self.progress_label = QLabel("")
        self.progress_label.setVisible(False)
        progress_layout.addWidget(self.progress_label)
        
        progress_group.setLayout(progress_layout)
        main_layout.addWidget(progress_group)
        
        # 日志组
        log_group = QGroupBox("推送日志")
        log_group.setContentsMargins(10, 15, 10, 10)  # 减少内边距，适应小窗口
        log_layout = QVBoxLayout()
        log_layout.setSpacing(5)  # 减少组件间距
        
        self.log_text = QTextEdit()
        self.log_text.setMinimumHeight(100)  # 最小高度，确保显示多行日志
        self.log_text.setMaximumHeight(180)  # 最大高度，提供更好的日志查看体验
        # 使用更合理的大小策略：水平扩展，垂直固定
        self.log_text.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        
        log_group.setLayout(log_layout)
        main_layout.addWidget(log_group)
        
        # 按钮组
        button_layout = QHBoxLayout()
        button_layout.setSpacing(15)  # 设置按钮之间的间距
        button_layout.setContentsMargins(0, 15, 0, 0)  # 设置上边距，避免与日志文本框重叠
        
        self.send_button = QPushButton("开始发送")
        self.send_button.setDefault(True)
        self.send_button.setMinimumHeight(35)  # 设置按钮最小高度
        button_layout.addWidget(self.send_button)
        
        self.cancel_button = QPushButton("取消发送")
        self.cancel_button.setEnabled(False)
        self.cancel_button.setMinimumHeight(35)  # 设置按钮最小高度
        button_layout.addWidget(self.cancel_button)
        
        self.close_button = QPushButton("关闭")
        self.close_button.setMinimumHeight(35)  # 设置按钮最小高度
        button_layout.addWidget(self.close_button)
        
        main_layout.addLayout(button_layout)
        
        self.setLayout(main_layout)
        
        # 连接数量变化信号
        self.latest_count_spinbox.valueChanged.connect(self.on_latest_count_changed)
        
        # 初始化推送范围选择状态
        self.on_export_range_changed()
    
    def eventFilter(self, obj, event):
        """事件过滤器，处理极小窗口情况"""
        # 由于移除了表格，不再需要此方法
        return super().eventFilter(obj, event)
    
    def handle_small_window(self):
        """处理极小窗口情况"""
        # 由于移除了表格，不再需要此方法
        pass
    
    def initialize_table_size(self):
        """初始化表格尺寸"""
        # 由于移除了表格，不再需要此方法
        pass
    
    def adjust_table_columns(self):
        """调整表格列宽以适应窗口宽度"""
        # 由于移除了表格，不再需要此方法
        pass
    
    def resizeEvent(self, event):
        """窗口大小变化事件处理"""
        # 由于移除了表格，不再需要此方法
        super().resizeEvent(event)
    
    def setup_connections(self):
        """设置信号连接"""
        self.send_button.clicked.connect(self.start_push)
        self.cancel_button.clicked.connect(self.cancel_push)
        self.close_button.clicked.connect(self.close)
        
        # 连接推送服务信号
        if self.push_service:
            self.push_service.push_started.connect(self.on_push_started)
            self.push_service.push_progress.connect(self.on_push_progress)
            self.push_service.push_completed.connect(self.on_push_completed)
            self.push_service.push_error.connect(self.on_push_error)
    
    def load_data(self):
        """加载数据"""
        try:
            # 初始化数据库管理器
            if not self.db_manager:
                self.db_manager = DatabaseManager() if DatabaseManager else None
            
            # 更新服务器状态
            self.update_server_status()
            
            # 定时器更新状态
            self.status_timer = QTimer()
            self.status_timer.timeout.connect(self.update_server_status)
            self.status_timer.start(2000)  # 每2秒更新一次
            
            # 如果有样本数据，则更新样本数量显示
            if self.samples:
                self.log_message(f"已加载 {len(self.samples)} 个样本")
            else:
                # 如果没有样本数据，尝试从数据库加载
                if self.db_manager:
                    try:
                        all_samples = self.db_manager.get_samples()
                        if all_samples:
                            # 按入库时间排序
                            def sort_key(sample):
                                if hasattr(sample, 'created_time') and sample.created_time:
                                    return sample.created_time
                                elif hasattr(sample, 'receive_time') and sample.receive_time:
                                    return sample.receive_time
                                else:
                                    return datetime.min
                            
                            all_samples.sort(key=sort_key, reverse=True)
                            self.samples = all_samples[:100] if len(all_samples) > 100 else all_samples
                            self.log_message(f"已从数据库加载 {len(self.samples)} 个样本")
                    except Exception as e:
                        logger.error(f"从数据库加载样本失败: {e}")
                        self.log_message("从数据库加载样本失败")
            
            # 初始化筛选状态
            self.on_export_range_changed()
            
        except Exception as e:
            logger.error(f"加载数据失败: {e}")
            self.log_message(f"加载数据失败: {e}")
    
    def load_recent_samples(self):
        """加载最近的样本"""
        try:
            if not self.db_manager:
                QMessageBox.warning(self, "警告", "数据库管理器未初始化")
                return
            
            # 加载所有样本（按入库时间倒序，最近的在前面）
            all_samples = self.db_manager.get_samples()
            
            # 按入库时间排序（created_time），如果没有则使用receive_time
            def sort_key(sample):
                if hasattr(sample, 'created_time') and sample.created_time:
                    return sample.created_time
                elif hasattr(sample, 'receive_time') and sample.receive_time:
                    return sample.receive_time
                else:
                    return datetime.min
            
            # 按时间倒序排序
            all_samples.sort(key=sort_key, reverse=True)
            
            # 取前100个作为最近样本
            self.samples = all_samples[:100] if len(all_samples) > 100 else all_samples
            self.load_sample_table()
            self.log_message(f"已加载 {len(self.samples)} 个最近样本（按入库时间排序）")
            
        except Exception as e:
            logger.error(f"加载最近样本失败: {e}")
            QMessageBox.critical(self, "错误", f"加载样本失败: {e}")
    
    def load_all_samples(self):
        """加载全部样本"""
        try:
            if not self.db_manager:
                QMessageBox.warning(self, "警告", "数据库管理器未初始化")
                return
            
            # 加载全部样本
            all_samples = self.db_manager.get_samples()
            
            # 按入库时间排序（created_time），如果没有则使用receive_time
            def sort_key(sample):
                if hasattr(sample, 'created_time') and sample.created_time:
                    return sample.created_time
                elif hasattr(sample, 'receive_time') and sample.receive_time:
                    return sample.receive_time
                else:
                    return datetime.min
            
            # 按时间倒序排序
            all_samples.sort(key=sort_key, reverse=True)
            self.samples = all_samples
            
            # 更新样本数量显示
            self.log_message(f"已加载全部 {len(self.samples)} 个样本（按入库时间排序）")
            
        except Exception as e:
            logger.error(f"加载全部样本失败: {e}")
            QMessageBox.critical(self, "错误", f"加载样本失败: {e}")
    
    def search_samples(self):
        """搜索样本"""
        try:
            if not self.db_manager:
                QMessageBox.warning(self, "警告", "数据库管理器未初始化")
                return
            
            search_term = self.search_input.text().strip()
            if not search_term:
                QMessageBox.warning(self, "警告", "请输入搜索关键词")
                return
            
            # 搜索样本
            search_results = self.db_manager.search_samples(search_term)
            
            # 按入库时间排序（created_time），如果没有则使用receive_time
            def sort_key(sample):
                if hasattr(sample, 'created_time') and sample.created_time:
                    return sample.created_time
                elif hasattr(sample, 'receive_time') and sample.receive_time:
                    return sample.receive_time
                else:
                    return datetime.min
            
            # 按时间倒序排序
            search_results.sort(key=sort_key, reverse=True)
            self.samples = search_results
            
            # 更新样本数量显示
            self.log_message(f"搜索 '{search_term}' 找到 {len(self.samples)} 个样本（按入库时间排序）")
            
        except Exception as e:
            logger.error(f"搜索样本失败: {e}")
            QMessageBox.critical(self, "错误", f"搜索样本失败: {e}")
    
    def refresh_sample_table(self):
        """刷新样本表格（已废弃，保留方法签名以兼容）"""
        try:
            # 由于移除了表格，此方法不再需要
            filtered_samples = self.get_filtered_samples()
            self.log_message(f"筛选后样本数量: {len(filtered_samples)}")
        except Exception as e:
            logger.error(f"刷新样本表格失败: {e}")
    
    def get_filtered_samples(self):
        """获取筛选后的样本列表"""
        try:
            if self.export_latest_radio.isChecked():
                count = self.latest_count_spinbox.value()
                # 按接收时间排序，获取最新的样本
                sorted_samples = sorted(self.samples, key=lambda x: x.receive_time, reverse=True)
                return sorted_samples[:count]
            elif self.export_time_range_radio.isChecked():
                start_date = self.start_date_edit.date().toPyDate()
                start_time = self.start_time_edit.time().toPyTime()
                end_date = self.end_date_edit.date().toPyDate()
                end_time = self.end_time_edit.time().toPyTime()
                
                # 组合完整的开始和结束时间
                start_datetime = datetime.combine(start_date, start_time)
                end_datetime = datetime.combine(end_date, end_time)
                
                # 筛选时间范围内的样本
                filtered_samples = []
                for sample in self.samples:
                    try:
                        # 优先使用样本分析时间
                        if hasattr(sample.sample_info, 'datetime') and sample.sample_info.datetime:
                            sample_datetime = datetime.strptime(sample.sample_info.datetime, "%Y-%m-%d %H:%M:%S")
                            if start_datetime <= sample_datetime <= end_datetime:
                                filtered_samples.append(sample)
                    except:
                        # 备用方案：使用接收时间
                        try:
                            sample_datetime = sample.receive_time
                            if start_datetime <= sample_datetime <= end_datetime:
                                filtered_samples.append(sample)
                        except:
                            continue
                
                return filtered_samples
            elif self.export_all_radio.isChecked():
                return self.samples
            elif self.export_current_page_radio.isChecked():
                return self.current_page_samples
            elif self.export_selected_radio.isChecked():
                return self.selected_samples
            else:
                return []
        except Exception as e:
            logger.error(f"获取筛选样本失败: {e}")
            return []
    
    def on_latest_count_changed(self):
        """最新样本数量改变事件"""
        if self.export_latest_radio.isChecked():
            count = self.latest_count_spinbox.value()
            self.log_message(f"将发送最新的 {count} 个样本")
    
    def set_today_range(self):
        """设置今天的时间范围"""
        today = datetime.now().date()
        self.start_date_edit.setDate(today)
        self.start_time_edit.setTime(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).time())
        self.end_date_edit.setDate(today)
        self.end_time_edit.setTime(datetime.now().replace(hour=23, minute=59, second=0, microsecond=0).time())
        self.on_export_range_changed()
    
    def set_yesterday_range(self):
        """设置昨天的时间范围"""
        yesterday = datetime.now().date() - timedelta(days=1)
        self.start_date_edit.setDate(yesterday)
        self.start_time_edit.setTime(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).time())
        self.end_date_edit.setDate(yesterday)
        self.end_time_edit.setTime(datetime.now().replace(hour=23, minute=59, second=0, microsecond=0).time())
        self.on_export_range_changed()
    
    def set_last_7_days_range(self):
        """设置最近7天的时间范围"""
        end_date = datetime.now().date()
        start_date = end_date - timedelta(days=6)  # 包含今天，所以是6天前
        self.start_date_edit.setDate(start_date)
        self.start_time_edit.setTime(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).time())
        self.end_date_edit.setDate(end_date)
        self.end_time_edit.setTime(datetime.now().replace(hour=23, minute=59, second=0, microsecond=0).time())
        self.on_export_range_changed()
    
    def set_last_30_days_range(self):
        """设置最近30天的时间范围"""
        end_date = datetime.now().date()
        start_date = end_date - timedelta(days=29)  # 包含今天，所以是29天前
        self.start_date_edit.setDate(start_date)
        self.start_time_edit.setTime(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).time())
        self.end_date_edit.setDate(end_date)
        self.end_time_edit.setTime(datetime.now().replace(hour=23, minute=59, second=0, microsecond=0).time())
        self.on_export_range_changed()
    
    def _initialize_export_range(self):
        """初始化推送范围选择状态（不记录日志）"""
        try:
            # 启用/禁用相关控件
            if hasattr(self, 'latest_count_spinbox'):
                self.latest_count_spinbox.setEnabled(self.export_latest_radio.isChecked())
            
            time_range_enabled = self.export_time_range_radio.isChecked()
            
            # 检查时间相关控件是否存在
            if hasattr(self, 'start_date_edit'):
                self.start_date_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'start_time_edit'):
                self.start_time_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'end_date_edit'):
                self.end_date_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'end_time_edit'):
                self.end_time_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'today_button'):
                self.today_button.setEnabled(time_range_enabled)
            if hasattr(self, 'yesterday_button'):
                self.yesterday_button.setEnabled(time_range_enabled)
            if hasattr(self, 'last_7_days_button'):
                self.last_7_days_button.setEnabled(time_range_enabled)
            if hasattr(self, 'last_30_days_button'):
                self.last_30_days_button.setEnabled(time_range_enabled)
        except Exception as e:
            logger.error(f"初始化推送范围选择状态失败: {e}")
    
    def on_export_range_changed(self):
        """导出范围改变事件"""
        try:
            # 启用/禁用相关控件
            if hasattr(self, 'latest_count_spinbox'):
                self.latest_count_spinbox.setEnabled(self.export_latest_radio.isChecked())
            
            time_range_enabled = self.export_time_range_radio.isChecked()
            
            # 检查时间相关控件是否存在
            if hasattr(self, 'start_date_edit'):
                self.start_date_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'start_time_edit'):
                self.start_time_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'end_date_edit'):
                self.end_date_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'end_time_edit'):
                self.end_time_edit.setEnabled(time_range_enabled)
            if hasattr(self, 'today_button'):
                self.today_button.setEnabled(time_range_enabled)
            if hasattr(self, 'yesterday_button'):
                self.yesterday_button.setEnabled(time_range_enabled)
            if hasattr(self, 'last_7_days_button'):
                self.last_7_days_button.setEnabled(time_range_enabled)
            if hasattr(self, 'last_30_days_button'):
                self.last_30_days_button.setEnabled(time_range_enabled)
            
            # 更新状态标签
            if self.export_latest_radio.isChecked():
                count = self.latest_count_spinbox.value() if hasattr(self, 'latest_count_spinbox') else 100
                self.log_message(f"将发送最新的 {count} 个样本")
            elif self.export_time_range_radio.isChecked():
                if hasattr(self, 'start_date_edit') and hasattr(self, 'start_time_edit') and hasattr(self, 'end_date_edit') and hasattr(self, 'end_time_edit'):
                    start_date = self.start_date_edit.date().toPyDate()
                    start_time = self.start_time_edit.time().toPyTime()
                    end_date = self.end_date_edit.date().toPyDate()
                    end_time = self.end_time_edit.time().toPyTime()
                    self.log_message(f"将发送 {start_date} {start_time.strftime('%H:%M')} 至 {end_date} {end_time.strftime('%H:%M')} 时间段的样本")
                else:
                    self.log_message("将按时间范围发送样本")
            elif self.export_all_radio.isChecked():
                sample_count = len(self.samples) if hasattr(self, 'samples') else 0
                self.log_message(f"将发送全部 {sample_count} 个样本")
            elif self.export_current_page_radio.isChecked():
                sample_count = len(self.current_page_samples) if hasattr(self, 'current_page_samples') else 0
                self.log_message(f"将发送当前页 {sample_count} 个样本")
            elif self.export_selected_radio.isChecked():
                sample_count = len(self.selected_samples) if hasattr(self, 'selected_samples') else 0
                if sample_count > 0:
                    self.log_message(f"将发送选中的 {sample_count} 个样本")
                else:
                    self.log_message("没有选中的样本")
        except Exception as e:
            logger.error(f"导出范围改变事件处理失败: {e}")
            # 如果出现错误，只打印到控制台
            print(f"[ERROR] 导出范围改变事件处理失败: {e}")
    
    def load_sample_table(self):
        """加载样本表格（已废弃，保留方法签名以兼容）"""
        # 由于移除了表格，此方法不再需要
        pass
    
    def on_selection_mode_changed(self):
        """选择模式改变事件（已废弃，保留方法签名以兼容）"""
        try:
            # 当选择模式改变时，更新样本数量显示
            filtered_samples = self.get_filtered_samples()
            self.log_message(f"筛选后样本数量: {len(filtered_samples)}")
        except Exception as e:
            logger.error(f"选择模式改变事件处理失败: {e}")
    
    def select_all_samples(self):
        """全选样本（已废弃，保留方法签名以兼容）"""
        # 由于移除了表格，此方法不再需要
        pass
    
    def deselect_all_samples(self):
        """取消全选样本（已废弃，保留方法签名以兼容）"""
        # 由于移除了表格，此方法不再需要
        pass
    
    def invert_selection(self):
        """反选样本（已废弃，保留方法签名以兼容）"""
        # 由于移除了表格，此方法不再需要
        pass
    
    def update_selected_count(self):
        """更新选中样本数量显示"""
        selected_count = len(self.selected_samples)
        if selected_count > 0:
            self.export_selected_radio.setText(f"仅发送选中样本 ({selected_count}个)")
            self.export_selected_radio.setEnabled(True)
        else:
            self.export_selected_radio.setText("仅发送选中样本 (无选中)")
            self.export_selected_radio.setEnabled(False)
            if self.export_selected_radio.isChecked():
                self.export_latest_radio.setChecked(True)
    
    def get_selected_samples(self):
        """获取选中的样本列表"""
        # 根据筛选条件获取样本
        filtered_samples = self.get_filtered_samples()
        
        # 否则返回筛选后的所有样本
        return filtered_samples
    
    def update_server_status(self):
        """更新服务器状态"""
        if not self.push_service:
            return
        
        # 更新服务器状态
        if self.push_service.get_client_count() > 0:
            self.server_status_label.setText("运行中")
            self.server_status_label.setStyleSheet("color: green;")
        else:
            self.server_status_label.setText("运行中 (无客户端)")
            self.server_status_label.setStyleSheet("color: orange;")
        
        # 更新客户端数量
        client_count = self.push_service.get_client_count()
        self.client_count_label.setText(str(client_count))
        
        # 更新客户端列表
        current_client = self.client_list_combo.currentData()
        self.client_list_combo.clear()
        self.client_list_combo.addItem("所有客户端", None)
        
        clients = self.push_service.get_connected_clients()
        for client_id in clients:
            self.client_list_combo.addItem(client_id, client_id)
        
        # 恢复之前的选择
        if current_client:
            index = self.client_list_combo.findData(current_client)
            if index >= 0:
                self.client_list_combo.setCurrentIndex(index)
    
    def start_push(self):
        """开始推送"""
        try:
            if not self.push_service:
                QMessageBox.warning(self, "警告", "推送服务未初始化")
                return
            
            client_count = self.push_service.get_client_count()
            self.log_message(f"当前客户端连接数: {client_count}")
            
            if client_count == 0:
                QMessageBox.warning(self, "警告", "没有客户端连接，无法推送数据")
                return
            
            if self.is_pushing:
                QMessageBox.warning(self, "警告", "推送正在进行中")
                return
            
            # 获取目标客户端
            self.selected_client = self.client_list_combo.currentData()
            self.log_message(f"选择的目标客户端: {self.selected_client}")
            
            # 获取选中的样本
            selected_samples = self.get_selected_samples()
            if not selected_samples:
                QMessageBox.warning(self, "警告", "请至少选择一个样本进行推送")
                return
            
            # 确认推送
            client_text = "所有客户端" if self.selected_client is None else self.selected_client
            reply = QMessageBox.question(
                self, "确认推送",
                f"确定要向 {client_text} 推送 {len(selected_samples)} 个样本吗？",
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            
            if reply == QMessageBox.StandardButton.Yes:
                self.log_message("开始推送样本...")
                self.is_pushing = True
                self.send_button.setEnabled(False)
                self.cancel_button.setEnabled(True)
                
                # 在新线程中执行推送
                import threading
                push_thread = threading.Thread(
                    target=self._push_samples,
                    daemon=True
                )
                push_thread.start()
                
        except Exception as e:
            logger.error(f"开始推送失败: {e}")
            QMessageBox.critical(self, "错误", f"开始推送失败: {e}")
    
    def _push_samples(self):
        """推送样本（在线程中执行）"""
        try:
            # 获取选中的样本和推送选项
            selected_samples = self.get_selected_samples()
            include_full_database = self.include_full_database_check.isChecked()
            self.log_message(f"开始批量推送，样本数量: {len(selected_samples)}, 目标客户端: {self.selected_client}, 完整数据库: {include_full_database}")
            result = self.push_service.push_sample_batch(selected_samples, self.selected_client, include_full_database)
            self.log_message(f"批量推送完成，结果: {result}")
            # 推送完成信号会在主线程中处理
        except Exception as e:
            logger.error(f"推送样本失败: {e}")
            self.log_message(f"推送异常: {e}")
            self.push_service.push_error.emit(str(e))
    
    def cancel_push(self):
        """取消推送"""
        if self.push_service:
            self.push_service.cancel_push()
            self.log_message("推送已取消")
        
        self.is_pushing = False
        self.send_button.setEnabled(True)
        self.cancel_button.setEnabled(False)
        self.progress_bar.setVisible(False)
        self.progress_label.setVisible(False)
    
    def on_push_started(self, total_count: int):
        """推送开始回调"""
        self.progress_bar.setVisible(True)
        self.progress_label.setVisible(True)
        self.progress_bar.setMaximum(total_count)
        self.progress_bar.setValue(0)
        self.progress_label.setText(f"准备推送 {total_count} 个样本...")
        self.log_message(f"开始推送 {total_count} 个样本")
    
    def on_push_progress(self, current: int, total: int):
        """推送进度回调"""
        self.progress_bar.setValue(current)
        self.progress_label.setText(f"正在推送: {current}/{total}")
    
    def on_push_completed(self, success_count: int, total_count: int):
        """推送完成回调"""
        self.is_pushing = False
        self.send_button.setEnabled(True)
        self.cancel_button.setEnabled(False)
        self.progress_bar.setVisible(False)
        self.progress_label.setVisible(False)
        
        self.log_message(f"推送完成: 成功 {success_count}/{total_count}")
        
        if success_count == total_count:
            QMessageBox.information(self, "成功", f"所有 {total_count} 个样本推送成功！")
        else:
            QMessageBox.warning(self, "部分成功", f"推送完成: 成功 {success_count}/{total_count} 个样本")
        
        # 发送完成信号
        result = {
            "success": success_count,
            "total": total_count
        }
        self.push_completed.emit(result)
    
    def on_push_error(self, error_msg: str):
        """推送错误回调"""
        self.log_message(f"推送错误: {error_msg}")
        QMessageBox.critical(self, "推送错误", error_msg)
    
    def log_message(self, message: str):
        """添加日志消息"""
        try:
            # 检查log_text组件是否存在
            if not hasattr(self, 'log_text') or self.log_text is None:
                # 如果log_text不存在，只打印到控制台
                print(f"[LOG] {message}")
                return
            
            timestamp = QTimer().remainingTime()  # 简单的时间戳
            log_text = f"[{timestamp}] {message}"
            self.log_text.append(log_text)
            
            # 滚动到底部
            scrollbar = self.log_text.verticalScrollBar()
            if scrollbar:
                scrollbar.setValue(scrollbar.maximum())
        except Exception as e:
            # 如果出现任何错误，只打印到控制台
            print(f"[LOG ERROR] {message}")
            print(f"[LOG ERROR] 错误详情: {e}")
    
    def closeEvent(self, event):
        """关闭事件"""
        if self.is_pushing:
            reply = QMessageBox.question(
                self, "确认关闭",
                "推送正在进行中，确定要关闭吗？",
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            
            if reply == QMessageBox.StandardButton.Yes:
                self.cancel_push()
                event.accept()
            else:
                event.ignore()
        else:
            event.accept() 